#pragma once

namespace intro
{

	class RTCamera
	{
	public:
		RTCamera();
		virtual ~RTCamera();

		void SetResolution(int width, int height) { _resolutionWidth = width; _resolutionHeight = height; }

		void SetPosition(const XMFLOAT3 & pos) { _position = pos; }
		const XMFLOAT3 & GetPosition() const { return _position; }

		void SetFieldOfViewRad(float fov) { _fieldOfViewRad = fov; }
		float GetFieldOfViewRad() { return _fieldOfViewRad; }

		void GetRayGenerationInfo(XMFLOAT3 & viewDir, XMFLOAT3 & rightToEnd, XMFLOAT3 & upToEnd) const
		{
			_direction.x = cosf(_xRot) * cosf(_yRot);
			_direction.y = sinf(_xRot);
			_direction.z = cosf(_xRot) * sinf(_yRot);

			XMVECTOR direction = XMLoadFloat3(&_direction);
			direction = XMVector3Normalize(direction);

			XMVECTOR right, realUp;
			XMFLOAT3 up(0.0f, 1.0f, 0.0f);
			right = XMVector3Cross(XMLoadFloat3(&up), direction);
			right = XMVector3Normalize(right);
			realUp = XMVector3Cross(direction, right);

			float projWid = 1.0f * tanf(_fieldOfViewRad * 0.5f);
			float projHei = projWid * _resolutionHeight / _resolutionWidth;

			XMStoreFloat3(&viewDir, direction);
			XMStoreFloat3(&rightToEnd, right * projWid * 0.5f);
			XMStoreFloat3(&upToEnd, realUp * projHei * 0.5f);

			XMStoreFloat3(&_direction, direction);
			XMStoreFloat3(&_right, right);
		}

		void MoveForward(float amount);
		void MoveBackward(float amount);
		void MoveRight(float amount);
		void MoveLeft(float amount);

		void RotateX(float amount) { _xRot += amount * _rotSpeed; }
		void RotateY(float amount) { _yRot += amount * _rotSpeed; }


	private:
		int _resolutionWidth;
		int _resolutionHeight;

		float _xRot;
		float _yRot;

		mutable XMFLOAT3 _direction;
		mutable XMFLOAT3 _right;

		XMFLOAT3 _position;


		float _fieldOfViewRad;

		float _moveSpeed;
		float _rotSpeed;

	};

}